<?php if(!defined('CALL')) exit('No direct script access allowed');

include_once 'lib/utils.class.php';
include_once 'lib/logger.class.php';
include_once 'models/db.class.php';

class mEvents
{
	public $actor_id = null;
	public $owner_id = null;
	public $city_id = null;
	public $show_share = FALSE;
	public $show_pub   = FALSE;
	public $show_sub   = TRUE;
	public $show_pri   = TRUE;
	
	public static $fields = 
		"SELECT
			e.id as event_id, e.dt, e.dt_beg, c.name as city, u.city_id, 
			e.part_0, e.part_1, e.part_2, e.part_3, e.access,
			u.id as user_id, u.username, u.face, e.note, u.note as user_note";
	
	public static function insert($uid, $date_uni, $time, $access, $note)
	{
		$eid = 0;
		$access = strtoupper($access);
		if(!self::testAccess($access)) return $eid;
		
		$p = str_split($time);
		$sql =
			"INSERT INTO events(user_id, dt_beg, part_0, part_1, part_2, part_3, access, note) ".
			"VALUES($uid, '$date_uni', '$p[0]','$p[1]','$p[2]','$p[3]', '$access', '$note')";
		
		if(LOG_SQL)	Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
			
		$res = DB::get()->query($sql);
		$event_id = DB::get()->insert_id();
		
		mMessages::for_event($event_id, $_SESSION['actor']);
		
		return $event_id;
	}
	
	public static function update($uid, $event_id, $date_uni, $time, $access, $note)
	{
		$eid = 0;
		$access = strtoupper($access);
		if(!self::testAccess($access)) return $eid;
		
		$p = str_split($time);
		$sql =
			"UPDATE events ".
			"SET dt_beg = '$date_uni', part_0 = '$p[0]', part_1 = '$p[1]', part_2 = '$p[2]', part_3 = '$p[3]', access = '$access', note = '$note' ".
			"WHERE id = $event_id and user_id = $uid";
		
		if(LOG_SQL) Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
		DB::get()->query($sql);
		$num = DB::get()->affected_rows();

		mMessages::for_event($event_id, $_SESSION['actor'], 'upd');
		return (bool)($num > 0);
	}
	
	public static function delete($uid, $event_id)
	{
		mMessages::for_event($event_id, $_SESSION['actor'], 'del');
		
		/// TODO удалять сначала записи из подчиненных таблиц
		$sql = "DELETE FROM events WHERE id = $event_id and user_id = $uid";

		if(LOG_SQL) Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
		DB::get()->query($sql);
		
		//return (bool)(DB::get()->affected_rows() > 0);
		return true;
	}
	
	public static function add_details($events, $actor_id)
	{
		$list_id = "";
		$index = array();
		foreach($events as $e)
		{
			$list_id .= ",".$e["event_id"];
			$index[] = $e["event_id"];
		}
		$list_id = '0'.$list_id;
		
		if(is_null($actor_id))
		{
			$user_props = "";
		}
		else
		{
			$user_props = "			
				(select count(id) > 0 from event_users where event_id = e.id and categ = 'WAN' and user_id = $actor_id) as has_wan,
				(select count(id) > 0 from event_users where event_id = e.id and categ = 'SHA' and user_id = $actor_id) as has_sha,
				(select count(id) > 0 from event_users where event_id = e.id and categ = 'SPA' and user_id = $actor_id) as has_spa,
				(select count(l.id) > 0 from user_links l where uid2 = e.user_id and uid1 = $actor_id and link_type = 'W') as watch,
				(select count(l.id) > 0 from user_links l where uid1 = e.user_id and uid2 = $actor_id and link_type = 'F') as friend,
				(select count(l.id) > 0 from user_links l where uid2 = e.user_id and uid1 = $actor_id and link_type = 'C') as cand,";
		}
		
		$sql =
			"SELECT
				e.id,".$user_props."
				(select count(id) from event_users where event_id = e.id and categ = 'COM') as num_com,
				(select count(id) from event_users where event_id = e.id and categ = 'WAN') as num_wan,
				(select count(id) from event_users where event_id = e.id and categ = 'SHA') as num_sha,
				(select count(id) from event_users where event_id = e.id and categ = 'SPA') as num_spa
			  FROM
				events e
			  WHERE
				e.id IN ($list_id)";
				
		if(LOG_SQL)
			Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
			
		$res = DB::get()->query($sql);
		while($row = DB::get()->fetch_assoc($res))
		{
			$i = array_search($row["id"], $index);
			// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$i = '.$i);
			$events[$i]["num_com"] = $row["num_com"];
			$events[$i]["has_wan"] = $row["has_wan"];
			$events[$i]["num_wan"] = $row["num_wan"];
			$events[$i]["has_sha"] = $row["has_sha"];
			$events[$i]["num_sha"] = $row["num_sha"];
			$events[$i]["has_spa"] = $row["has_spa"];
			$events[$i]["num_spa"] = $row["num_spa"];
			$events[$i]["watch"]   = $row["watch"];
			$events[$i]["friend"]  = $row["friend"];
			$events[$i]["cand"]    = $row["cand"];
		}
		DB::get()->free_result($res);
		//Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, print_r($events, true));
		
		return $events;
	}
	
	public static function generate_sql(
		// кто смотрит 
		$actor_id = null, 
		// выбранный
		$selected_id = null,
		// город авторов
		$city_id = null,
		// опорная дата
		$date_uni = null,
		// с участием актора
		$share = FALSE,
		// только подписку актора
		$sub = FALSE,
		// только события актора
		$own = FALSE
	)
	{
		/*
		- События выбранного пользователя (личные - только для актора, а закрытые, если выбранный пользователь доверяет актору)
		- События с участием выбранного пользователя (только для актора)
		- Подписка выбранного пользователя (только для актора)
		- Все доступные события (все публичные + все закрытые от доверяемых + личные + фильтр по городу)
		*/

		// все пользователи
		if($selected_id == 0) $selected_id = null;
		
		// если выбранный пользователь не установлен, то считаем,
		// что выбранным актора
		if(is_null($selected_id)) $selected_id = $actor_id;
		
		
		// Список полей
		$select = self::$fields;
		$union = "\n UNION DISTINCT\n".$select;
		$u = "";

		if(is_null($date_uni)) $date_uni = date("Y-m-d");
		// все города
		if($city_id == 0) $city_id = null;
		if($city_id == "null") $city_id = null;
		$city_condition = is_null($city_id) ? "" : "\n   AND u.city_id = ".$city_id;
		$by_user = ($selected_id == $actor_id) ? "" : "\n-- смотрим конкретного автора\n   AND u.id = $selected_id";
		// если смотрим события у конкретного пользователя,
		// то фильтр по городу отключаем
		if(!empty($by_user)) $city_condition = "";
		
		// ЗАЩИТА ОТ СПАМА (только для открытых планов)
		// нужно дать пользователям возможность закрывать события
		// индексации в поисковых системах, для чего
		// при неавторизованном входе показываются только те сообщения,
		// для которых было у пользователей было время их пометить как спам,
		// но они их не пометили
		$spam_condition = is_null($actor_id) ? "\n AND spam = 0 AND datediff(dt_beg, dt) > 2" : "";
		
		// Открытые планы
		$from_pub =
			"\n FROM events e, users u, cities c "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			   ."AND e.access = 'A'"
			   .$city_condition
			   .$spam_condition
			   .$by_user;
		
		// Закрытые события тех, кто доверяет актору
		$from_friends =
			"\n  FROM events e, users u, cities c, user_links f "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			."\n-- f.uid2 - тот, кто сделал другом uid2 \n"
			   ."AND f.uid2 = $actor_id "
			   ."AND f.uid1 = u.id "
			   ."AND f.link_type = 'F' "
			."\n-- разрешаем доступ только к событиям для друзей \n"
			   ."AND e.access = 'F' "
			   .$city_condition
			   .$by_user;

 		// Открытые планы тех, за кем актор следит
		$from_pub_watched =
			"\n  FROM events e, users u, cities c, user_links w "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			   ."\n-- w.uid1 - тот, кто следит за uid2 \n"
			   ."AND w.uid1 = $actor_id "
			   ."AND w.uid2 = u.id "
			   ."AND w.link_type = 'W' "
				."\n-- разрешаем доступ только к событиям для всех \n"
			   ."AND e.access = 'A'"
			   // .$city_condition
			   .$by_user;  
		
		$from_friends_watched =
			"\n  FROM events e, users u, cities c, user_links w, user_links f "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			."\n-- w.uid1 - тот, кто следит за uid2  \n"
			   ."AND w.uid1 = $actor_id "
			   ."AND w.uid2 = u.id "
			   ."AND w.link_type = 'W' "
			."\n-- f.uid2 - тот, кто сделал другом uid2 \n"
			   ."AND f.uid2 = $actor_id "
			   ."AND f.uid1 = u.id "
			   ."AND f.link_type = 'F' "
			."\n-- разрешаем доступ только к событиям для друзей \n"
			   ."AND e.access = 'F' "
			   // .$city_condition
			   .$by_user;
			
		$from_share =
			"\n FROM events e, users u, cities c, event_users eu "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			   ."\n-- ue.event_id - участник события \n"
			   ."AND e.id = eu.event_id "
			   ."AND eu.categ = 'SHA' "
			   ."AND eu.user_id = $actor_id"
			   // .$city_condition
			   .$by_user;
   
		$from_actor =
			"\n  FROM events e, users u, cities c "
			 ."WHERE e.user_id = u.id AND u.city_id = c.id "
			   ."###COND.DATE### "
			   ."###COND.SEARCH###"
			   ."AND u.id = $actor_id"
			   .$by_user;
			
		// Если актор неавторизован, то показываются только публичные события
		if(is_null($actor_id))
		{
			Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor is null');
			$select .= $from_pub;
		}
		// Если выбран не актор, то актору доступен только просмотр
		// событий выбранного актора и то с учетом доверенности
		elseif($selected_id != $actor_id)
		{
			// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor != $selected');
			$select .=
				$from_pub.
				$union.
				$from_friends;
		}
		// Актор выбрал себя, и может просматривать:
		else
		{
			// свои
			if($own)
			{
				// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor смотрит свои');
				$select .= $from_actor;
			}
			// подписку
			elseif($sub)
			{
				// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor смотрит подписку');
				$select .=
					$from_pub_watched.
					$union.
					$from_friends_watched;
			}
			// с участием актора (включая свои)
			elseif($share)
			{
				// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor смотрит где участвует');
				$select .=
					$from_share.
					$union.
					$from_actor;
			}
			// все доступные (открытьые, друзей и свои)
			else
			{
				// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, '$actor смотрит все доступные');
				$select .=
					$from_pub.
					$union.
					$from_friends;
					// $from_friends.$union.$from_actor;
			}
		}

		// Добавим опорную дату, чтобы потом ее можно было
		// легко извлечь и вставить в нужном виде
		$select = "-- ".$date_uni."\n".$select;
		
		// if(LOG_SQL)	Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $select);
		return $select;
	}

	public static function read($select, $row_beg, $row_num, $dir, $actor_id, $search = null)
	{
		$events = array();
		
		$date_uni = substr($select, 3, 10);
		$date_subst = $dir ? ">= '".$date_uni."'" : "< '".$date_uni."'";
		$date_subst = "AND e.dt_beg ".$date_subst; 
		$select = str_replace('###COND.DATE###', $date_subst, $select);
		
		if(!is_null($search))
			$select = str_replace("###COND.SEARCH###", " AND MATCH(e.note) against('$search') ", $select);
		else
			$select = str_replace("###COND.SEARCH###", "", $select);
		
		// сортировка событий - кривая, т.к. даты сортируются правильно
		// в соответствии с порциями данных, а время суток - нет
		$order_date = $dir ? "" : "DESC";
		$order_time = $dir ? "DESC" : "";
		
		if(is_null($search) || TRUE)
			$select .= "\n ORDER BY dt_beg $order_date, part_0 $order_time, part_1 $order_time, part_2 $order_time, part_3 $order_time";
		$select .= "\n LIMIT $row_beg, $row_num";
		
		if(LOG_SQL) Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, "SQL: ".$select);
		
		$res = DB::get()->query($select);
		$num_rows = DB::get()->num_rows($res);
		if($num_rows > 0)
		{
			$i = 0;
			while($row = DB::get()->fetch_assoc($res))
			{
				$row['note'] = Utils::safe_encode($row['note']);
				$row['user_note'] = Utils::safe_encode($row['user_note']);
				$events[] = $row;
				$i++;
			}	
			DB::get()->free_result($res);
		}
		// Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, "selected: ".$num_rows);
		
		$events = self::add_details($events, $actor_id);
		
		if($dir)
			return $events;
		else
			return array_reverse($events);
	}
	
	public static function get($id)
	{
		if(empty($id)) return null;
		
		$sql = self::$fields." FROM events e, users u, cities c WHERE e.id = $id AND u.id = e.user_id AND u.city_id = c.id";
		if(LOG_SQL) Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, "SQL: ".$sql);
		$res = DB::get()->query($sql);
		$num_rows = DB::get()->num_rows($res);
		if(DB::get()->num_rows($res) > 0)
		{
			$row = DB::get()->fetch_assoc($res);
			$row['note'] = Utils::safe_encode($row['note']);
			$row['user_note'] = Utils::safe_encode($row['user_note']);
			DB::get()->free_result($res);
			return $row;
		}
		return null;
	}
	
	// Получение события с проверкой прав
	public static function get2($event_id, $actor)
	{
		// получаем событие из базы по его ID
		$event = self::get($event_id);
		
		if($event == null) return null;
		
		// если это событие актора, то он имеет доступ к нему
		if($event['user_id'] == $actor->id) return $event;
		
		// если это событие публичное, то актор также может видеть его
		if($event['access'] == 'A') return $event;
		
		// если это чужое приватное событие, тогда у актора нет к нему доступа
		if($event['access'] == 'P') return null;
		
		// если это событие доступное только для доверенных лиц,
		// то нужно убедиться, что владелец события доверяет актору
		if(array_search($event['user_id'], $actor->links['FS']) === FALSE)
			return null;
		else
			return $event;
	}
	
	public static function spam_add($id, $num)
	{
		$sql = "UPDATE events SET spam = spam + $num WHERE id = $id";
		if(LOG_SQL)	Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
		DB::get()->query($sql);
		
		if($num < 0)
		{
			$sql = "UPDATE events SET spam = 0 WHERE id = $id AND spam < 0";
			if(LOG_SQL)	Logger::Write(__FILE__." ".__FUNCTION__." line: ".__LINE__, $sql);
			DB::get()->query($sql);
		}
	}
	
	private static function testAccess($value)
	{
		return preg_match('/^[AFP]$/', $value) != FALSE;
	}
	
}